/*
 * main implementation: use this 'C' sample to create your own application
 *
 */

#include "derivative.h" /* include peripheral declarations */
#include "3_OS/OS_TaskManagement.h"

#include "3_OS/OS_Alarms.h"
#include "3_OS/OS_Mailbox.h"
#include "1_HAL/HAL_XTAL.h"
#include "1_HAL/HAL_PIT.h"
#include "1_HAL/HAL_GPIO.h"
#include "1_HAL/HAL_ISR.h"

#define period 100

u32 Duty1,Duty2,Duty3,Duty4,Duty5,Duty6;

u32 MB_ID,MB_UART_ID,MB_UART2_ID,
	MB_UART3_ID,MB_UART4_ID;

u32 ALR_AID, ALR_BID, ALR_CID, 
	ALR_DID, ALR_EID, ALR_FID,
	ALR_GID, ALR_HID, ALR_IID, 
	ALR_JID;

u32 A_ID, B_ID, C_ID, MBProd_ID, MBCons_ID,PWM1_ID, 
	PWM2_ID, PWM3_ID, PWM4_ID, PWM5_ID, PWM6_ID, 
	loop_ID, ReadSerial1_ID, ReadSerial2_ID, ReadSerial3_ID,
	ReadSerial4_ID;

u32 i,k;

void Funct_A(void);
void Funct_B(void);
void Funct_C(void);

void loop (void)
{
	do{
		i++;
		k++;
	}while(1);
}

void Funct_A(void) {
	i++;
	OS_ActivateTask(B_ID);
	i++;
	OS_TerminateCurrentTask();
}

void Funct_B(void) {
	i--;
	OS_ChainTask(C_ID);
}

void Funct_C(void) {
	i--;
	OS_TerminateCurrentTask();
}
void MBProd1(void){
	OS_WriteMailbox(MB_ID, ++i);
	OS_TerminateCurrentTask();
}
void MBCons1(void){
	OS_ReadMailbox(MB_ID, &i);
	OS_TerminateCurrentTask();
}

void PWM1(void) {
	OS_ReadMailbox(MB_UART_ID, &Duty1);
	if (Duty1 > 100) Duty1 = 100;
	if (GPIOB_PDOR & BIT0)
	{
		GPIOB_PCOR = BIT0;
		OS_ChangeTicksAlarm(period-Duty1, ALR_AID);
	}
	else
	{
		GPIOB_PSOR = BIT0;
		OS_ChangeTicksAlarm(Duty1, ALR_AID);
	}
	OS_TerminateCurrentTask();
}

void PWM2(void) {
	OS_ReadMailbox(MB_UART2_ID, &Duty2);
	if (Duty2 > 100) Duty2 = 100;
	if (GPIOB_PDOR & BIT1)
	{
		GPIOB_PCOR = BIT1;
		OS_ChangeTicksAlarm(period-Duty2, ALR_BID);
	}
	else
	{
		GPIOB_PSOR = BIT1;
		OS_ChangeTicksAlarm(Duty2, ALR_BID);
	}
	OS_TerminateCurrentTask();
}

void PWM3(void) {
	OS_ReadMailbox(MB_UART3_ID, &Duty3);
	if (Duty3 > 100) Duty3 = 100;
	if (GPIOB_PDOR & BIT2)
	{
		GPIOB_PCOR = BIT2;
		OS_ChangeTicksAlarm(period-Duty3, ALR_CID);
	}
	else
	{
		GPIOB_PSOR = BIT2;
		OS_ChangeTicksAlarm(Duty3, ALR_CID);
	}
	OS_TerminateCurrentTask();
}

void PWM4(void) {
	OS_ReadMailbox(MB_UART4_ID, &Duty4);
	if (Duty4 > 100) Duty4 = 100;
	if (GPIOB_PDOR & BIT3)
	{
		GPIOB_PCOR = BIT3;
		OS_ChangeTicksAlarm(period-Duty4, ALR_DID);
	}
	else
	{
		GPIOB_PSOR = BIT3;
		OS_ChangeTicksAlarm(Duty4, ALR_DID);
	}
	OS_TerminateCurrentTask();
}

void PWM5(void) {
	if (GPIOC_PDOR & BIT2)
	{
		GPIOC_PCOR = BIT2;
		OS_ChangeTicksAlarm(period-Duty5, ALR_EID);
	}
	else
	{
		GPIOC_PSOR = BIT2;
		OS_ChangeTicksAlarm(Duty5, ALR_EID);
	}
	OS_TerminateCurrentTask();
}

void PWM6(void) {
	if (GPIOC_PDOR & BIT1)
	{
		GPIOC_PCOR = BIT1;
		OS_ChangeTicksAlarm(period-Duty6, ALR_FID);
	}
	else
	{
		GPIOC_PSOR = BIT1;
		OS_ChangeTicksAlarm(Duty6, ALR_FID);
	}
	OS_TerminateCurrentTask();
}

void ReadSerial1(void)
{
	static u32 input = 0;
	static u32 bit = 0;
	static GPIO_MemMapPtr portDevice = PTD_BASE_PTR;
	static u32 pin = BIT2;
	switch(bit)
	{
		case 0:
			OS_ChangeTicksAlarm(7, ALR_GID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT0;
			}
			bit++;
			break;
		case 1:
			OS_ChangeTicksAlarm(6, ALR_GID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT1;
			}
			bit++;
			break;
		case 2:
			OS_ChangeTicksAlarm(7, ALR_GID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT2;
			}
			bit++;
			break;
		case 3:
			OS_ChangeTicksAlarm(7, ALR_GID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT3;
			}
			bit++;
			break;
		case 4:
			OS_ChangeTicksAlarm(6, ALR_GID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT4;
			}
			bit++;
			break;
		case 5:
			OS_ChangeTicksAlarm(7, ALR_GID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT5;
			}
			bit++;
			break;
		case 6:
			OS_ChangeTicksAlarm(7, ALR_GID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT6;
			}
			bit++;
			break;
		case 7:
			OS_ChangeTicksAlarm(6, ALR_GID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT7;
			}
			bit++;
			break;
		case 8:
			//Destroy the alarm of the task
			OS_DestroyAlarm(ALR_GID);
			//Write in the mailbox
			OS_WriteMailbox(MB_UART_ID, input);
			//Clear the variables for next use
			input = 0;
			bit = 0;
			//Activate again the interruption
			HAL_GPIO_Init_Interrupt(portDevice, pin);
			break;
		default:
			break;
	}
	OS_TerminateCurrentTask();
}

void FallingEdgeSerial1 (void)
{
	//No more interruptions on this pin
	HAL_GPIO_Clear_Interrupt(PTD_BASE_PTR, BIT2);
	//Creates an alarm for reading the pin
	OS_CreateAlarm(PERIODIC, 8, ReadSerial1_ID, &ALR_GID);
}

void ReadSerial2(void)
{
	static u32 input = 0;
	static u32 bit = 0;
	static GPIO_MemMapPtr portDevice = PTD_BASE_PTR;
	static u32 pin = BIT3;
	switch(bit)
	{
		case 0:
			OS_ChangeTicksAlarm(7, ALR_HID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT0;
			}
			bit++;
			break;
		case 1:
			OS_ChangeTicksAlarm(6, ALR_HID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT1;
			}
			bit++;
			break;
		case 2:
			OS_ChangeTicksAlarm(7, ALR_HID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT2;
			}
			bit++;
			break;
		case 3:
			OS_ChangeTicksAlarm(7, ALR_HID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT3;
			}
			bit++;
			break;
		case 4:
			OS_ChangeTicksAlarm(6, ALR_HID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT4;
			}
			bit++;
			break;
		case 5:
			OS_ChangeTicksAlarm(7, ALR_HID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT5;
			}
			bit++;
			break;
		case 6:
			OS_ChangeTicksAlarm(7, ALR_HID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT6;
			}
			bit++;
			break;
		case 7:
			OS_ChangeTicksAlarm(6, ALR_HID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT7;
			}
			bit++;
			break;
		case 8:
			//Destroy the alarm of the task
			OS_DestroyAlarm(ALR_HID);
			//Write in the mailbox
			OS_WriteMailbox(MB_UART2_ID, input);
			//Clear the variables for next use
			input = 0;
			bit = 0;
			//Activate again the interruption
			HAL_GPIO_Init_Interrupt(portDevice, pin);
			break;
		default:
			break;
	}
	OS_TerminateCurrentTask();
}

void FallingEdgeSerial2 (void)
{
	//No more interruptions on this pin
	HAL_GPIO_Clear_Interrupt(PTD_BASE_PTR, BIT3);
	//Creates an alarm for reading the pin
	OS_CreateAlarm(PERIODIC, 8, ReadSerial2_ID, &ALR_HID);
}

void ReadSerial3(void)
{
	static u32 input = 0;
	static u32 bit = 0;
	static GPIO_MemMapPtr portDevice = PTD_BASE_PTR;
	static u32 pin = BIT1;
	switch(bit)
	{
		case 0:
			OS_ChangeTicksAlarm(7, ALR_IID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT0;
			}
			bit++;
			break;
		case 1:
			OS_ChangeTicksAlarm(6, ALR_IID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT1;
			}
			bit++;
			break;
		case 2:
			OS_ChangeTicksAlarm(7, ALR_IID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT2;
			}
			bit++;
			break;
		case 3:
			OS_ChangeTicksAlarm(7, ALR_IID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT3;
			}
			bit++;
			break;
		case 4:
			OS_ChangeTicksAlarm(6, ALR_IID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT4;
			}
			bit++;
			break;
		case 5:
			OS_ChangeTicksAlarm(7, ALR_IID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT5;
			}
			bit++;
			break;
		case 6:
			OS_ChangeTicksAlarm(7, ALR_IID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT6;
			}
			bit++;
			break;
		case 7:
			OS_ChangeTicksAlarm(6, ALR_IID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT7;
			}
			bit++;
			break;
		case 8:
			//Destroy the alarm of the task
			OS_DestroyAlarm(ALR_IID);
			//Write in the mailbox
			OS_WriteMailbox(MB_UART3_ID, input);
			//Clear the variables for next use
			input = 0;
			bit = 0;
			//Activate again the interruption
			HAL_GPIO_Init_Interrupt(portDevice, pin);
			break;
		default:
			break;
	}
	OS_TerminateCurrentTask();
}

void FallingEdgeSerial3 (void)
{
	//No more interruptions on this pin
	HAL_GPIO_Clear_Interrupt(PTD_BASE_PTR, BIT1);
	//Creates an alarm for reading the pin
	OS_CreateAlarm(PERIODIC, 8, ReadSerial3_ID, &ALR_IID);
}

void ReadSerial4(void)
{
	static u32 input = 0;
	static u32 bit = 0;
	static GPIO_MemMapPtr portDevice = PTA_BASE_PTR;
	static u32 pin = BIT16;
	switch(bit)
	{
		case 0:
			OS_ChangeTicksAlarm(7, ALR_JID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT0;
			}
			bit++;
			break;
		case 1:
			OS_ChangeTicksAlarm(6, ALR_JID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT1;
			}
			bit++;
			break;
		case 2:
			OS_ChangeTicksAlarm(7, ALR_JID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT2;
			}
			bit++;
			break;
		case 3:
			OS_ChangeTicksAlarm(7, ALR_JID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT3;
			}
			bit++;
			break;
		case 4:
			OS_ChangeTicksAlarm(6, ALR_JID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT4;
			}
			bit++;
			break;
		case 5:
			OS_ChangeTicksAlarm(7, ALR_JID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT5;
			}
			bit++;
			break;
		case 6:
			OS_ChangeTicksAlarm(7, ALR_JID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT6;
			}
			bit++;
			break;
		case 7:
			OS_ChangeTicksAlarm(6, ALR_JID);
			if (GPIO_PDD_GetPortDataInput(portDevice) & pin)
			{
				input |= BIT7;
			}
			bit++;
			break;
		case 8:
			//Destroy the alarm of the task
			OS_DestroyAlarm(ALR_JID);
			//Write in the mailbox
			OS_WriteMailbox(MB_UART4_ID, input);
			//Clear the variables for next use
			input = 0;
			bit = 0;
			//Activate again the interruption
			HAL_GPIO_Init_Interrupt(portDevice, pin);
			break;
		default:
			break;
	}
	OS_TerminateCurrentTask();
}

void FallingEdgeSerial4 (void)
{
	//No more interruptions on this pin
	HAL_GPIO_Clear_Interrupt(PTA_BASE_PTR, BIT16);
	//Creates an alarm for reading the pin
	OS_CreateAlarm(PERIODIC, 8, ReadSerial4_ID, &ALR_JID);
}

int main(void) {

	DisableInterrupts;
	//Predefined duty cycles
	Duty1 = 50;
	Duty2 = 50;
	Duty3 = 50;
	Duty4 = 50;
	Duty5 = 90;
	Duty6 = 80;
	
	//Output pins for the PWMs
	HAL_GPIO_Init_Output(PTB_BASE_PTR, BIT0|BIT1|BIT2|BIT3);
	HAL_GPIO_Init_Output(PTC_BASE_PTR, BIT1|BIT2);
	
	//Pins for the UART reading
	HAL_GPIO_Init_Interrupt(PTD_BASE_PTR, BIT2 | BIT3 | BIT1);
	HAL_GPIO_Init_Interrupt(PTA_BASE_PTR, BIT16);

	//PIT initialisation
	InitClock();
	HAL_PIT_Init();
	OS_InitAlarm();

	//Test Tasks
	OS_CreateTask(3, 0, 1, FULL, Funct_A, &A_ID);
	OS_CreateTask(2, 0, 1, FULL, Funct_B, &B_ID);
	OS_CreateTask(1, 0, 1, FULL, Funct_C, &C_ID);
	
	//Test Tasks with mailboxes
	OS_CreateTask(5, 0, 1, FULL, MBCons1, &MBCons_ID);	
	OS_CreateTask(5, 0, 1, FULL, MBProd1, &MBProd_ID);
	
	//Tasks and alarms for PWMs
	OS_CreateTask(4, 0, 1, FULL, PWM1, &PWM1_ID);
	OS_CreateTask(4, 0, 1, FULL, PWM2, &PWM2_ID);
	OS_CreateTask(4, 0, 1, FULL, PWM3, &PWM3_ID);
	OS_CreateTask(4, 0, 1, FULL, PWM4, &PWM4_ID);
	OS_CreateTask(4, 0, 1, FULL, PWM5, &PWM5_ID);
	OS_CreateTask(4, 0, 1, FULL, PWM6, &PWM6_ID);
	
	OS_CreateAlarm(PERIODIC, Duty1, PWM1_ID, &ALR_AID);
	OS_CreateAlarm(PERIODIC, Duty2, PWM2_ID, &ALR_BID);
	OS_CreateAlarm(PERIODIC, Duty3, PWM3_ID, &ALR_CID);
	OS_CreateAlarm(PERIODIC, Duty4, PWM4_ID, &ALR_DID);
	OS_CreateAlarm(PERIODIC, Duty5, PWM5_ID, &ALR_EID);
	OS_CreateAlarm(PERIODIC, Duty6, PWM6_ID, &ALR_FID);
	
	//UART testing
	OS_CreateTask(3, 0, 1, FULL, ReadSerial1, &ReadSerial1_ID);
	HAL_GPIO1_RegisterISRCallback((void(*)(void))FallingEdgeSerial1);
	
	OS_CreateTask(3, 0, 1, FULL, ReadSerial2, &ReadSerial2_ID);
	HAL_GPIO2_RegisterISRCallback((void(*)(void))FallingEdgeSerial2);
	
	OS_CreateTask(3, 0, 1, FULL, ReadSerial3, &ReadSerial3_ID);
	HAL_GPIO3_RegisterISRCallback((void(*)(void))FallingEdgeSerial3);
	
	OS_CreateTask(3, 0, 1, FULL, ReadSerial4, &ReadSerial4_ID);
	HAL_GPIO4_RegisterISRCallback((void(*)(void))FallingEdgeSerial4);
	
	//Creation of Mailboxes
	OS_CreateMailbox(MBProd_ID, MBCons_ID, &MB_ID);
	OS_CreateMailbox(ReadSerial1_ID, PWM1_ID, &MB_UART_ID);
	OS_CreateMailbox(ReadSerial2_ID, PWM2_ID, &MB_UART2_ID);
	OS_CreateMailbox(ReadSerial3_ID, PWM3_ID, &MB_UART3_ID);
	OS_CreateMailbox(ReadSerial4_ID, PWM4_ID, &MB_UART4_ID);
	
	EnableInterrupts;
	for (;;) {
		OS_Schedule();
	}
	return 0;
}
